export {};

/** 泛型与接口*/
interface add{
  (a: number, b: number): number;
}

// let numberAdd: add = (a2: number, b2: number) => {
//   return a2 + b2;
// };

interface anyAdd<T> {
  (a: T, b: T): T;
}

/** 泛型什么时候传递实参,要看泛型修饰的目标什么时候被调用 */
let stringAdd: anyAdd<string> = (a2: string, b2: string) => {
  return a2 + b2;
};

let numberAdd: anyAdd<number> = (a2: number, b2: number) => {
  return a2 + b2;
};


/** 如果一个泛型接口要用在定义一个类型的时候就需要确定类型, 那么这个<T>应该放在interface上
 *  否则如果一个泛型接口是要在运行时（泛型函数调用时）才能确定类型, 那么这个<T>应该放在interface内的声明的函数类型的前面 */

// ×
interface ICreateArray<T>/** ←这个泛型不应该放在接口上了, 而是应该放在接口里描述的某个类型上(放在外面也可以但你要在下面ICreateArray传入一个实参泛型, 但这样类型就确定 并不是我们期望的 我们期望的是在实际调用时才确定类型 而不是定义的时候就确定了)*/ {
  (times: number, val: T):T[]
  //↑ 应该改成 ↓
  // <T>(times: number, val: T):T[]
}
const createArray: ICreateArray = <T>(times: number, val: T) => {
  let result = [];
  for (let i = 0; i < times; i++) {
    result.push(val)
  }
  return result;
};

// √
/*
interface ICreateArray {
  <T>(times: number, val: T):T[]
}
const createArray: ICreateArray = <T>(times: number, val: T) => {
  let result = [];
  for (let i = 0; i < times; i++) {
    result.push(val)
  }
  return result;
};
*/
